package top.tenebrous.termbor.rpc.provider.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.tenebrous.termbor.rpc.provider.handler.RpcProviderHandler;
import top.tenebrous.termbor.rpc.registry.RegistryService;
import top.tenebrous.termbor.rpc.registry.config.RegistryConfig;
import top.tenebrous.termbor.rpc.serialization.codec.RpcDecoder;
import top.tenebrous.termbor.rpc.serialization.codec.RpcEncoder;
import top.tenebrous.termbor.rpc.spi.loader.ExtensionLoader;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program: termbor-rpc
 * @description:
 * @author: yazhang6
 * @create: 2024-05-20 18:22
 **/
public class BaseService implements Server{

    private final Logger logger = LoggerFactory.getLogger(BaseService.class);

    protected String host = "127.0.0.1";

    protected int port = 9527;

    private final String reflectType;

    protected Map<String, Object> handlerMap = new ConcurrentHashMap<>();

    protected RegistryService registryService;

    public BaseService(String serverAddress, String registryAddress, String registryType, String registryLoadBalanceType, String reflectType) {
        if (!StringUtils.isEmpty(serverAddress)) {
            String[] serverArray = serverAddress.split(":");
            this.host = serverArray[0];
            this.port = Integer.parseInt(serverArray[1]);
        }
        this.reflectType = reflectType;
        this.registryService = this.getRegistryService(registryAddress, registryType, registryLoadBalanceType);

    }

    private RegistryService getRegistryService(String registryAddress, String registryType, String registryLoadBalanceType) {
        RegistryService registryService = null;
        try {
            registryService = ExtensionLoader.getExtension(RegistryService.class, registryType);
            registryService.init(new RegistryConfig(registryAddress, registryType, registryLoadBalanceType));
        } catch (Exception e) {
            logger.error("RPC server init error", e);
        }
        return registryService;
    }

    @Override
    public void start() {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
            serverBootstrap.group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new RpcEncoder());
                        pipeline.addLast(new RpcDecoder());
                        pipeline.addLast(new RpcProviderHandler(reflectType ,handlerMap));
                    }
                })
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);
            ChannelFuture future = serverBootstrap.bind(host, port).sync();
            logger.info("服务提供方启动成功，地址：{}:{}", host, port);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            worker.shutdownGracefully();
            boss.shutdownGracefully();
        }
    }

    @Override
    public void shutdown() {

    }

}
